home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / lib / xulrunner-1.9.1.5 / components / nsUrlClassifierLib.js < prev    next >
Text File  |  2009-11-09  |  51KB  |  1,596 lines

  1. //@line 37 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierLib.js"
  2.  
  3. // We wastefully reload the same JS files across components.  This puts all
  4. // the common JS files used by safebrowsing and url-classifier into a
  5. // single component.
  6.  
  7. const Cc = Components.classes;
  8. const Ci = Components.interfaces;
  9. const G_GDEBUG = false;
  10.  
  11. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/lang.js"
  12.  
  13.  
  14. /**
  15.  * lang.js - Some missing JavaScript language features
  16.  */
  17.  
  18. /**
  19.  * Partially applies a function to a particular "this object" and zero or
  20.  * more arguments. The result is a new function with some arguments of the first
  21.  * function pre-filled and the value of |this| "pre-specified".
  22.  *
  23.  * Remaining arguments specified at call-time are appended to the pre-
  24.  * specified ones.
  25.  *
  26.  * Usage:
  27.  * var barMethBound = BindToObject(myFunction, myObj, "arg1", "arg2");
  28.  * barMethBound("arg3", "arg4");
  29.  *
  30.  * @param fn {string} Reference to the function to be bound
  31.  *
  32.  * @param self {object} Specifies the object which |this| should point to
  33.  * when the function is run. If the value is null or undefined, it will default
  34.  * to the global object.
  35.  *
  36.  * @returns {function} A partially-applied form of the speficied function.
  37.  */
  38. function BindToObject(fn, self, opt_args) {
  39.   var boundargs = fn.boundArgs_ || [];
  40.   boundargs = boundargs.concat(Array.slice(arguments, 2, arguments.length));
  41.  
  42.   if (fn.boundSelf_)
  43.     self = fn.boundSelf_;
  44.   if (fn.boundFn_)
  45.     fn = fn.boundFn_;
  46.  
  47.   var newfn = function() {
  48.     // Combine the static args and the new args into one big array
  49.     var args = boundargs.concat(Array.slice(arguments));
  50.     return fn.apply(self, args);
  51.   }
  52.  
  53.   newfn.boundArgs_ = boundargs;
  54.   newfn.boundSelf_ = self;
  55.   newfn.boundFn_ = fn;
  56.  
  57.   return newfn;
  58. }
  59.  
  60. /**
  61.  * Inherit the prototype methods from one constructor into another.
  62.  *
  63.  * Usage:
  64.  *
  65.  * function ParentClass(a, b) { }
  66.  * ParentClass.prototype.foo = function(a) { }
  67.  *
  68.  * function ChildClass(a, b, c) {
  69.  *   ParentClass.call(this, a, b);
  70.  * }
  71.  *
  72.  * ChildClass.inherits(ParentClass);
  73.  *
  74.  * var child = new ChildClass("a", "b", "see");
  75.  * child.foo(); // works
  76.  *
  77.  * In addition, a superclass' implementation of a method can be invoked
  78.  * as follows:
  79.  *
  80.  * ChildClass.prototype.foo = function(a) {
  81.  *   ChildClass.superClass_.foo.call(this, a);
  82.  *   // other code
  83.  * };
  84.  */
  85. Function.prototype.inherits = function(parentCtor) {
  86.   var tempCtor = function(){};
  87.   tempCtor.prototype = parentCtor.prototype;
  88.   this.superClass_ = parentCtor.prototype;
  89.   this.prototype = new tempCtor();
  90. }
  91. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/preferences.js"
  92.  
  93.  
  94. // Class for manipulating preferences. Aside from wrapping the pref
  95. // service, useful functionality includes:
  96. //
  97. // - abstracting prefobserving so that you can observe preferences
  98. //   without implementing nsIObserver 
  99. // 
  100. // - getters that return a default value when the pref doesn't exist 
  101. //   (instead of throwing)
  102. // 
  103. // - get-and-set getters
  104. //
  105. // Example:
  106. // 
  107. // var p = new PROT_Preferences();
  108. // dump(p.getPref("some-true-pref"));     // shows true
  109. // dump(p.getPref("no-such-pref", true)); // shows true   
  110. // dump(p.getPref("no-such-pref", null)); // shows null
  111. //
  112. // function observe(prefThatChanged) {
  113. //   dump("Pref changed: " + prefThatChanged);
  114. // };
  115. //
  116. // p.addObserver("somepref", observe);
  117. // p.setPref("somepref", true);            // dumps
  118. // p.removeObserver("somepref", observe);
  119. //
  120. // TODO: should probably have the prefobserver pass in the new and old
  121. //       values
  122.  
  123. // TODO(tc): Maybe remove this class and just call natively since we're no
  124. //           longer an extension.
  125.  
  126. /**
  127.  * A class that wraps the preferences service.
  128.  *
  129.  * @param opt_startPoint        A starting point on the prefs tree to resolve 
  130.  *                              names passed to setPref and getPref.
  131.  *
  132.  * @param opt_useDefaultPranch  Set to true to work against the default 
  133.  *                              preferences tree instead of the profile one.
  134.  *
  135.  * @constructor
  136.  */
  137. function G_Preferences(opt_startPoint, opt_getDefaultBranch) {
  138.   this.debugZone = "prefs";
  139.   this.observers_ = {};
  140.   this.getDefaultBranch_ = !!opt_getDefaultBranch;
  141.  
  142.   this.startPoint_ = opt_startPoint || null;
  143. }
  144.  
  145. G_Preferences.setterMap_ = { "string": "setCharPref",
  146.                              "boolean": "setBoolPref",
  147.                              "number": "setIntPref" };
  148.  
  149. G_Preferences.getterMap_ = {};
  150. G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_STRING] = "getCharPref";
  151. G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_BOOL] = "getBoolPref";
  152. G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_INT] = "getIntPref";
  153.  
  154. G_Preferences.prototype.__defineGetter__('prefs_', function() {
  155.   var prefs;
  156.   var prefSvc = Cc["@mozilla.org/preferences-service;1"]
  157.                   .getService(Ci.nsIPrefService);
  158.  
  159.   if (this.getDefaultBranch_) {
  160.     prefs = prefSvc.getDefaultBranch(this.startPoint_);
  161.   } else {
  162.     prefs = prefSvc.getBranch(this.startPoint_);
  163.   }
  164.  
  165.   // QI to prefs in case we want to add observers
  166.   prefs.QueryInterface(Ci.nsIPrefBranchInternal);
  167.   return prefs;
  168. });
  169.  
  170. /**
  171.  * Stores a key/value in a user preference. Valid types for val are string,
  172.  * boolean, and number. Complex values are not yet supported (but feel free to
  173.  * add them!).
  174.  */
  175. G_Preferences.prototype.setPref = function(key, val) {
  176.   var datatype = typeof(val);
  177.  
  178.   if (datatype == "number" && (val % 1 != 0)) {
  179.     throw new Error("Cannot store non-integer numbers in preferences.");
  180.   }
  181.  
  182.   var meth = G_Preferences.setterMap_[datatype];
  183.  
  184.   if (!meth) {
  185.     throw new Error("Pref datatype {" + datatype + "} not supported.");
  186.   }
  187.  
  188.   return this.prefs_[meth](key, val);
  189. }
  190.  
  191. /**
  192.  * Retrieves a user preference. Valid types for the value are the same as for
  193.  * setPref. If the preference is not found, opt_default will be returned 
  194.  * instead.
  195.  */
  196. G_Preferences.prototype.getPref = function(key, opt_default) {
  197.   var type = this.prefs_.getPrefType(key);
  198.  
  199.   // zero means that the specified pref didn't exist
  200.   if (type == Ci.nsIPrefBranch.PREF_INVALID) {
  201.     return opt_default;
  202.   }
  203.  
  204.   var meth = G_Preferences.getterMap_[type];
  205.  
  206.   if (!meth) {
  207.     throw new Error("Pref datatype {" + type + "} not supported.");
  208.   }
  209.  
  210.   // If a pref has been cleared, it will have a valid type but won't
  211.   // be gettable, so this will throw.
  212.   try {
  213.     return this.prefs_[meth](key);
  214.   } catch(e) {
  215.     return opt_default;
  216.   }
  217. }
  218.  
  219. /**
  220.  * Delete a preference. 
  221.  *
  222.  * @param which Name of preference to obliterate
  223.  */
  224. G_Preferences.prototype.clearPref = function(which) {
  225.   try {
  226.     // This throws if the pref doesn't exist, which is fine because a 
  227.     // non-existent pref is cleared
  228.     this.prefs_.clearUserPref(which);
  229.   } catch(e) {}
  230. }
  231.  
  232. /**
  233.  * Add an observer for a given pref.
  234.  *
  235.  * @param which String containing the pref to listen to
  236.  * @param callback Function to be called when the pref changes. This
  237.  *                 function will receive a single argument, a string 
  238.  *                 holding the preference name that changed
  239.  */
  240. G_Preferences.prototype.addObserver = function(which, callback) {
  241.   // Need to store the observer we create so we can eventually unregister it
  242.   if (!this.observers_[which])
  243.     this.observers_[which] = { callbacks: [], observers: [] };
  244.  
  245.   /* only add an observer if the callback hasn't been registered yet */
  246.   if (this.observers_[which].callbacks.indexOf(callback) == -1) {
  247.     var observer = new G_PreferenceObserver(callback);
  248.     this.observers_[which].callbacks.push(callback);
  249.     this.observers_[which].observers.push(observer);
  250.     this.prefs_.addObserver(which, observer, false /* strong reference */);
  251.   }
  252. }
  253.  
  254. /**
  255.  * Remove an observer for a given pref.
  256.  *
  257.  * @param which String containing the pref to stop listening to
  258.  * @param callback Function to remove as an observer
  259.  */
  260. G_Preferences.prototype.removeObserver = function(which, callback) {
  261.   var ix = this.observers_[which].callbacks.indexOf(callback);
  262.   G_Assert(this, ix != -1, "Tried to unregister a nonexistant observer"); 
  263.   this.observers_[which].callbacks.splice(ix, 1);
  264.   var observer = this.observers_[which].observers.splice(ix, 1)[0];
  265.   this.prefs_.removeObserver(which, observer);
  266. }
  267.  
  268. /**
  269.  * Remove all preference observers registered through this object.
  270.  */
  271. G_Preferences.prototype.removeAllObservers = function() {
  272.   for (var which in this.observers_) {
  273.     for each (var observer in this.observers_[which].observers) {
  274.       this.prefs_.removeObserver(which, observer);
  275.     }
  276.   }
  277.   this.observers_ = {};
  278. }
  279.  
  280. /**
  281.  * Helper class that knows how to observe preference changes and
  282.  * invoke a callback when they do
  283.  *
  284.  * @constructor
  285.  * @param callback Function to call when the preference changes
  286.  */
  287. function G_PreferenceObserver(callback) {
  288.   this.debugZone = "prefobserver";
  289.   this.callback_ = callback;
  290. }
  291.  
  292. /**
  293.  * Invoked by the pref system when a preference changes. Passes the
  294.  * message along to the callback.
  295.  *
  296.  * @param subject The nsIPrefBranch that changed
  297.  * @param topic String "nsPref:changed" (aka 
  298.  *              NS_PREFBRANCH_PREFCHANGE_OBSERVER_ID -- but where does it
  299.  *              live???)
  300.  * @param data Name of the pref that changed
  301.  */
  302. G_PreferenceObserver.prototype.observe = function(subject, topic, data) {
  303.   G_Debug(this, "Observed pref change: " + data);
  304.   this.callback_(data);
  305. }
  306.  
  307. /**
  308.  * XPCOM cruft
  309.  *
  310.  * @param iid Interface id of the interface the caller wants
  311.  */
  312. G_PreferenceObserver.prototype.QueryInterface = function(iid) {
  313.   if (iid.equals(Ci.nsISupports) || 
  314.       iid.equals(Ci.nsIObserver) ||
  315.       iid.equals(Ci.nsISupportsWeakReference))
  316.     return this;
  317.   throw Components.results.NS_ERROR_NO_INTERFACE;
  318. }
  319.  
  320. //@line 38 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/debug.js"
  321.  
  322. //@line 868 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/debug.js"
  323.  
  324. // Stubs for the debugging aids scattered through this component.
  325. // They will be expanded if you compile yourself a debug build.
  326.  
  327. function G_Debug(who, msg) { }
  328. function G_Assert(who, condition, msg) { }
  329. function G_Error(who, msg) { }
  330. var G_debugService = { __noSuchMethod__: function() { } };
  331.  
  332. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/alarm.js"
  333.  
  334.  
  335. // An Alarm fires a callback after a certain amount of time, or at
  336. // regular intervals. It's a convenient replacement for
  337. // setTimeout/Interval when you don't want to bind to a specific
  338. // window.
  339. //
  340. // The ConditionalAlarm is an Alarm that cancels itself if its callback 
  341. // returns a value that type-converts to true.
  342. //
  343. // Example:
  344. //
  345. //  function foo() { dump('hi'); };
  346. //  new G_Alarm(foo, 10*1000);                   // Fire foo in 10 seconds
  347. //  new G_Alarm(foo, 10*1000, true /*repeat*/);  // Fire foo every 10 seconds
  348. //  new G_Alarm(foo, 10*1000, true, 7);          // Fire foo every 10 seconds
  349. //                                               // seven times
  350. //  new G_ConditionalAlarm(foo, 1000, true); // Fire every sec until foo()==true
  351. //
  352. //  // Fire foo every 10 seconds until foo returns true or until it fires seven
  353. //  // times, whichever happens first.
  354. //  new G_ConditionalAlarm(foo, 10*1000, true /*repeating*/, 7);
  355. //
  356. // TODO: maybe pass an isFinal flag to the callback if they opted to
  357. // set maxTimes and this is the last iteration?
  358.  
  359.  
  360. /**
  361.  * Set an alarm to fire after a given amount of time, or at specific 
  362.  * intervals.
  363.  *
  364.  * @param callback Function to call when the alarm fires
  365.  * @param delayMS Number indicating the length of the alarm period in ms
  366.  * @param opt_repeating Boolean indicating whether this should fire 
  367.  *                      periodically
  368.  * @param opt_maxTimes Number indicating a maximum number of times to 
  369.  *                     repeat (obviously only useful when opt_repeating==true)
  370.  */
  371. function G_Alarm(callback, delayMS, opt_repeating, opt_maxTimes) {
  372.   this.debugZone = "alarm";
  373.   this.callback_ = callback;
  374.   this.repeating_ = !!opt_repeating;
  375.   this.timer_ = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  376.   var type = opt_repeating ? 
  377.              this.timer_.TYPE_REPEATING_SLACK : 
  378.              this.timer_.TYPE_ONE_SHOT;
  379.   this.maxTimes_ = opt_maxTimes ? opt_maxTimes : null;
  380.   this.nTimes_ = 0;
  381.  
  382.   this.observerServiceObserver_ = new G_ObserverServiceObserver(
  383.                                         'xpcom-shutdown',
  384.                                         BindToObject(this.cancel, this));
  385.  
  386.   // Ask the timer to use nsITimerCallback (.notify()) when ready
  387.   this.timer_.initWithCallback(this, delayMS, type);
  388. }
  389.  
  390. /**
  391.  * Cancel this timer 
  392.  */
  393. G_Alarm.prototype.cancel = function() {
  394.   if (!this.timer_) {
  395.     return;
  396.   }
  397.  
  398.   this.timer_.cancel();
  399.   // Break circular reference created between this.timer_ and the G_Alarm
  400.   // instance (this)
  401.   this.timer_ = null;
  402.   this.callback_ = null;
  403.  
  404.   // We don't need the shutdown observer anymore
  405.   this.observerServiceObserver_.unregister();
  406. }
  407.  
  408. /**
  409.  * Invoked by the timer when it fires
  410.  * 
  411.  * @param timer Reference to the nsITimer which fired (not currently 
  412.  *              passed along)
  413.  */
  414. G_Alarm.prototype.notify = function(timer) {
  415.   // fire callback and save results
  416.   var ret = this.callback_();
  417.   
  418.   // If they've given us a max number of times to fire, enforce it
  419.   this.nTimes_++;
  420.   if (this.repeating_ && 
  421.       typeof this.maxTimes_ == "number" 
  422.       && this.nTimes_ >= this.maxTimes_) {
  423.     this.cancel();
  424.   } else if (!this.repeating_) {
  425.     // Clear out the callback closure for TYPE_ONE_SHOT timers
  426.     this.cancel();
  427.   }
  428.   // We don't cancel/cleanup timers that repeat forever until either
  429.   // xpcom-shutdown occurs or cancel() is called explicitly.
  430.  
  431.   return ret;
  432. }
  433.  
  434. G_Alarm.prototype.setDelay = function(delay) {
  435.   this.timer_.delay = delay;
  436. }
  437.  
  438. /**
  439.  * XPCOM cruft
  440.  */
  441. G_Alarm.prototype.QueryInterface = function(iid) {
  442.   if (iid.equals(Components.interfaces.nsISupports) ||
  443.       iid.equals(Components.interfaces.nsITimerCallback))
  444.     return this;
  445.  
  446.   throw Components.results.NS_ERROR_NO_INTERFACE;
  447. }
  448.  
  449.  
  450. /**
  451.  * An alarm with the additional property that it cancels itself if its 
  452.  * callback returns true.
  453.  *
  454.  * For parameter documentation, see G_Alarm
  455.  */
  456. function G_ConditionalAlarm(callback, delayMS, opt_repeating, opt_maxTimes) {
  457.   G_Alarm.call(this, callback, delayMS, opt_repeating, opt_maxTimes);
  458.   this.debugZone = "conditionalalarm";
  459. }
  460.  
  461. G_ConditionalAlarm.inherits(G_Alarm);
  462.  
  463. /**
  464.  * Invoked by the timer when it fires
  465.  * 
  466.  * @param timer Reference to the nsITimer which fired (not currently 
  467.  *              passed along)
  468.  */
  469. G_ConditionalAlarm.prototype.notify = function(timer) {
  470.   // Call G_Alarm::notify
  471.   var rv = G_Alarm.prototype.notify.call(this, timer);
  472.  
  473.   if (this.repeating_ && rv) {
  474.     G_Debug(this, "Callback of a repeating alarm returned true; cancelling.");
  475.     this.cancel();
  476.   }
  477. }
  478. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/cryptohasher.js"
  479.  
  480.  
  481. // A very thin wrapper around nsICryptoHash. It's not strictly
  482. // necessary, but makes the code a bit cleaner and gives us the
  483. // opportunity to verify that our implementations give the results that
  484. // we expect, for example if we have to interoperate with a server.
  485. //
  486. // The digest* methods reset the state of the hasher, so it's
  487. // necessary to call init() explicitly after them.
  488. //
  489. // Works only in Firefox 1.5+.
  490. //
  491. // IMPORTANT NOTE: Due to https://bugzilla.mozilla.org/show_bug.cgi?id=321024
  492. // you cannot use the cryptohasher before app-startup. The symptom of doing
  493. // so is a segfault in NSS.
  494.  
  495. /**
  496.  * Instantiate a new hasher. You must explicitly call init() before use!
  497.  */
  498. function G_CryptoHasher() {
  499.   this.debugZone = "cryptohasher";
  500.   this.hasher_ = null;
  501. }
  502.  
  503. G_CryptoHasher.algorithms = {
  504.   MD2: Ci.nsICryptoHash.MD2,
  505.   MD5: Ci.nsICryptoHash.MD5,
  506.   SHA1: Ci.nsICryptoHash.SHA1,
  507.   SHA256: Ci.nsICryptoHash.SHA256,
  508.   SHA384: Ci.nsICryptoHash.SHA384,
  509.   SHA512: Ci.nsICryptoHash.SHA512,
  510. };
  511.  
  512. /**
  513.  * Initialize the hasher. This function must be called after every call
  514.  * to one of the digest* methods.
  515.  *
  516.  * @param algorithm Constant from G_CryptoHasher.algorithms specifying the
  517.  *                  algorithm this hasher will use
  518.  */ 
  519. G_CryptoHasher.prototype.init = function(algorithm) {
  520.   var validAlgorithm = false;
  521.   for (var alg in G_CryptoHasher.algorithms)
  522.     if (algorithm == G_CryptoHasher.algorithms[alg])
  523.       validAlgorithm = true;
  524.  
  525.   if (!validAlgorithm)
  526.     throw new Error("Invalid algorithm: " + algorithm);
  527.  
  528.   this.hasher_ = Cc["@mozilla.org/security/hash;1"]
  529.                  .createInstance(Ci.nsICryptoHash);
  530.   this.hasher_.init(algorithm);
  531. }
  532.  
  533. /**
  534.  * Update the hash's internal state with input given in a string. Can be
  535.  * called multiple times for incrementeal hash updates.
  536.  *
  537.  * @param input String containing data to hash.
  538.  */ 
  539. G_CryptoHasher.prototype.updateFromString = function(input) {
  540.   if (!this.hasher_)
  541.     throw new Error("You must initialize the hasher first!");
  542.  
  543.   var stream = Cc['@mozilla.org/io/string-input-stream;1']
  544.                .createInstance(Ci.nsIStringInputStream);
  545.   stream.setData(input, input.length);
  546.   this.updateFromStream(stream);
  547. }
  548.  
  549. /**
  550.  * Update the hash's internal state with input given in an array. Can be
  551.  * called multiple times for incremental hash updates.
  552.  *
  553.  * @param input Array containing data to hash.
  554.  */ 
  555. G_CryptoHasher.prototype.updateFromArray = function(input) {
  556.   if (!this.hasher_)
  557.     throw new Error("You must initialize the hasher first!");
  558.  
  559.   this.hasher_.update(input, input.length);
  560. }
  561.  
  562. /**
  563.  * Update the hash's internal state with input given in a stream. Can be
  564.  * called multiple times from incremental hash updates.
  565.  */
  566. G_CryptoHasher.prototype.updateFromStream = function(stream) {
  567.   if (!this.hasher_)
  568.     throw new Error("You must initialize the hasher first!");
  569.  
  570.   if (stream.available())
  571.     this.hasher_.updateFromStream(stream, stream.available());
  572. }
  573.  
  574. /**
  575.  * @returns The hash value as a string (sequence of 8-bit values)
  576.  */ 
  577. G_CryptoHasher.prototype.digestRaw = function() {
  578.   var digest = this.hasher_.finish(false /* not b64 encoded */);
  579.   this.hasher_ = null;
  580.   return digest;
  581. }
  582.  
  583. /**
  584.  * @returns The hash value as a base64-encoded string
  585.  */ 
  586. G_CryptoHasher.prototype.digestBase64 = function() {
  587.   var digest = this.hasher_.finish(true /* b64 encoded */);
  588.   this.hasher_ = null;
  589.   return digest;
  590. }
  591.  
  592. /**
  593.  * @returns The hash value as a hex-encoded string
  594.  */ 
  595. G_CryptoHasher.prototype.digestHex = function() {
  596.   var raw = this.digestRaw();
  597.   return this.toHex_(raw);
  598. }
  599.  
  600. /**
  601.  * Converts a sequence of values to a hex-encoded string. The input is a
  602.  * a string, so you can stick 16-bit values in each character.
  603.  *
  604.  * @param str String to conver to hex. (Often this is just a sequence of
  605.  *            16-bit values)
  606.  *
  607.  * @returns String containing the hex representation of the input
  608.  */ 
  609. G_CryptoHasher.prototype.toHex_ = function(str) {
  610.   var hexchars = '0123456789ABCDEF';
  611.   var hexrep = new Array(str.length * 2);
  612.  
  613.   for (var i = 0; i < str.length; ++i) {
  614.     hexrep[i * 2] = hexchars.charAt((str.charCodeAt(i) >> 4) & 15);
  615.     hexrep[i * 2 + 1] = hexchars.charAt(str.charCodeAt(i) & 15);
  616.   }
  617.   return hexrep.join('');
  618. }
  619.  
  620. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/observer.js"
  621.  
  622.  
  623. // A couple of classes to simplify creating observers. 
  624. //
  625. // // Example1:
  626. //
  627. // function doSomething() { ... }
  628. // var observer = new G_ObserverWrapper(topic, doSomething);
  629. // someObj.addObserver(topic, observer);
  630. //
  631. // // Example2: 
  632. //
  633. // function doSomething() { ... }
  634. // new G_ObserverServiceObserver("profile-after-change", 
  635. //                               doSomething,
  636. //                               true /* run only once */);
  637.  
  638.  
  639. /**
  640.  * This class abstracts the admittedly simple boilerplate required of
  641.  * an nsIObserver. It saves you the trouble of implementing the
  642.  * indirection of your own observe() function.
  643.  *
  644.  * @param topic String containing the topic the observer will filter for
  645.  *
  646.  * @param observeFunction Reference to the function to call when the 
  647.  *                        observer fires
  648.  *
  649.  * @constructor
  650.  */
  651. function G_ObserverWrapper(topic, observeFunction) {
  652.   this.debugZone = "observer";
  653.   this.topic_ = topic;
  654.   this.observeFunction_ = observeFunction;
  655. }
  656.  
  657. /**
  658.  * XPCOM
  659.  */
  660. G_ObserverWrapper.prototype.QueryInterface = function(iid) {
  661.   if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIObserver))
  662.     return this;
  663.   throw Components.results.NS_ERROR_NO_INTERFACE;
  664. }
  665.  
  666. /**
  667.  * Invoked by the thingy being observed
  668.  */
  669. G_ObserverWrapper.prototype.observe = function(subject, topic, data) {
  670.   if (topic == this.topic_)
  671.     this.observeFunction_(subject, topic, data);
  672. }
  673.  
  674.  
  675. /**
  676.  * This class abstracts the admittedly simple boilerplate required of
  677.  * observing an observerservice topic. It implements the indirection
  678.  * required, and automatically registers to hear the topic.
  679.  *
  680.  * @param topic String containing the topic the observer will filter for
  681.  *
  682.  * @param observeFunction Reference to the function to call when the 
  683.  *                        observer fires
  684.  *
  685.  * @param opt_onlyOnce Boolean indicating if the observer should unregister
  686.  *                     after it has fired
  687.  *
  688.  * @constructor
  689.  */
  690. function G_ObserverServiceObserver(topic, observeFunction, opt_onlyOnce) {
  691.   this.debugZone = "observerserviceobserver";
  692.   this.topic_ = topic;
  693.   this.observeFunction_ = observeFunction;
  694.   this.onlyOnce_ = !!opt_onlyOnce;
  695.   
  696.   this.observer_ = new G_ObserverWrapper(this.topic_, 
  697.                                          BindToObject(this.observe_, this));
  698.   this.observerService_ = Cc["@mozilla.org/observer-service;1"]
  699.                           .getService(Ci.nsIObserverService);
  700.   this.observerService_.addObserver(this.observer_, this.topic_, false);
  701. }
  702.  
  703. /**
  704.  * Unregister the observer from the observerservice
  705.  */
  706. G_ObserverServiceObserver.prototype.unregister = function() {
  707.   this.observerService_.removeObserver(this.observer_, this.topic_);
  708.   this.observerService_ = null;
  709. }
  710.  
  711. /**
  712.  * Invoked by the observerservice
  713.  */
  714. G_ObserverServiceObserver.prototype.observe_ = function(subject, topic, data) {
  715.   this.observeFunction_(subject, topic, data);
  716.   if (this.onlyOnce_)
  717.     this.unregister();
  718. }
  719.  
  720. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/moz/protocol4.js"
  721.  
  722.  
  723. // A helper class that knows how to parse from and serialize to
  724. // protocol4. This is a simple, historical format used by some Google
  725. // interfaces, for example the Toolbar (i.e., ancient services).
  726. //
  727. // Protocol4 consists of a newline-separated sequence of name/value
  728. // pairs (strings). Each line consists of the name, the value length,
  729. // and the value itself, all separated by colons. Example:
  730. //
  731. // foo:6:barbaz\n
  732. // fritz:33:issickofdynamicallytypedlanguages\n
  733.  
  734.  
  735. /**
  736.  * This class knows how to serialize/deserialize maps to/from their
  737.  * protocol4 representation.
  738.  *
  739.  * @constructor
  740.  */
  741. function G_Protocol4Parser() {
  742.   this.debugZone = "protocol4";
  743.  
  744.   this.protocol4RegExp_ = new RegExp("([^:]+):\\d+:(.*)$");
  745.   this.newlineRegExp_ = new RegExp("(\\r)?\\n");
  746. }
  747.  
  748. /**
  749.  * Create a map from a protocol4 string. Silently skips invalid lines.
  750.  *
  751.  * @param text String holding the protocol4 representation
  752.  * 
  753.  * @returns Object as an associative array with keys and values 
  754.  *          given in text. The empty object is returned if none
  755.  *          are parsed.
  756.  */
  757. G_Protocol4Parser.prototype.parse = function(text) {
  758.  
  759.   var response = {};
  760.   if (!text)
  761.     return response;
  762.  
  763.   // Responses are protocol4: (repeated) name:numcontentbytes:content\n
  764.   var lines = text.split(this.newlineRegExp_);
  765.   for (var i = 0; i < lines.length; i++)
  766.     if (this.protocol4RegExp_.exec(lines[i]))
  767.       response[RegExp.$1] = RegExp.$2;
  768.  
  769.   return response;
  770. }
  771.  
  772. /**
  773.  * Create a protocol4 string from a map (object). Throws an error on 
  774.  * an invalid input.
  775.  *
  776.  * @param map Object as an associative array with keys and values 
  777.  *            given as strings.
  778.  *
  779.  * @returns text String holding the protocol4 representation
  780.  */
  781. G_Protocol4Parser.prototype.serialize = function(map) {
  782.   if (typeof map != "object")
  783.     throw new Error("map must be an object");
  784.  
  785.   var text = "";
  786.   for (var key in map) {
  787.     if (typeof map[key] != "string")
  788.       throw new Error("Keys and values must be strings");
  789.     
  790.     text += key + ":" + map[key].length + ":" + map[key] + "\n";
  791.   }
  792.   
  793.   return text;
  794. }
  795.  
  796. //@line 53 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierLib.js"
  797.  
  798. /* ***** BEGIN LICENSE BLOCK *****
  799.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  800.  *
  801.  * The contents of this file are subject to the Mozilla Public License Version
  802.  * 1.1 (the "License"); you may not use this file except in compliance with
  803.  * the License. You may obtain a copy of the License at
  804.  * http://www.mozilla.org/MPL/
  805.  *
  806.  * Software distributed under the License is distributed on an "AS IS" basis,
  807.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  808.  * for the specific language governing rights and limitations under the
  809.  * License.
  810.  *
  811.  * The Original Code is Google Safe Browsing.
  812.  *
  813.  * The Initial Developer of the Original Code is Google Inc.
  814.  * Portions created by the Initial Developer are Copyright (C) 2006
  815.  * the Initial Developer. All Rights Reserved.
  816.  *
  817.  * Contributor(s):
  818.  *   Tony Chang <tc@google.com> (original author)
  819.  *
  820.  * Alternatively, the contents of this file may be used under the terms of
  821.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  822.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  823.  * in which case the provisions of the GPL or the LGPL are applicable instead
  824.  * of those above. If you wish to allow use of your version of this file only
  825.  * under the terms of either the GPL or the LGPL, and not to allow others to
  826.  * use your version of this file under the terms of the MPL, indicate your
  827.  * decision by deleting the provisions above and replace them with the notice
  828.  * and other provisions required by the GPL or the LGPL. If you do not delete
  829.  * the provisions above, a recipient may use your version of this file under
  830.  * the terms of any one of the MPL, the GPL or the LGPL.
  831.  *
  832.  * ***** END LICENSE BLOCK ***** */
  833.  
  834. // This implements logic for stopping requests if the server starts to return
  835. // too many errors.  If we get MAX_ERRORS errors in ERROR_PERIOD minutes, we
  836. // back off for TIMEOUT_INCREMENT minutes.  If we get another error
  837. // immediately after we restart, we double the timeout and add
  838. // TIMEOUT_INCREMENT minutes, etc.
  839. // 
  840. // This is similar to the logic used by the search suggestion service.
  841.  
  842. // HTTP responses that count as an error.  We also include any 5xx response
  843. // as an error.
  844. const HTTP_FOUND                 = 302;
  845. const HTTP_SEE_OTHER             = 303;
  846. const HTTP_TEMPORARY_REDIRECT    = 307;
  847.  
  848. /**
  849.  * @param maxErrors Number of times to request before backing off.
  850.  * @param retryIncrement Time (ms) for each retry before backing off.
  851.  * @param maxRequests Number the number of requests needed to trigger backoff
  852.  * @param requestPeriod Number time (ms) in which maxRequests have to occur to
  853.  *     trigger the backoff behavior
  854.  * @param timeoutIncrement Number time (ms) the starting timeout period
  855.  *     we double this time for consecutive errors
  856.  * @param maxTimeout Number time (ms) maximum timeout period
  857.  */
  858. function RequestBackoff(maxErrors, retryIncrement,
  859.                         maxRequests, requestPeriod,
  860.                         timeoutIncrement, maxTimeout) {
  861.   this.MAX_ERRORS_ = maxErrors;
  862.   this.RETRY_INCREMENT_ = retryIncrement;
  863.   this.MAX_REQUESTS_ = maxRequests;
  864.   this.REQUEST_PERIOD_ = requestPeriod;
  865.   this.TIMEOUT_INCREMENT_ = timeoutIncrement;
  866.   this.MAX_TIMEOUT_ = maxTimeout;
  867.  
  868.   // Queue of ints keeping the time of all requests
  869.   this.requestTimes_ = [];
  870.  
  871.   this.numErrors_ = 0;
  872.   this.errorTimeout_ = 0;
  873.   this.nextRequestTime_ = 0;
  874. }
  875.  
  876. /**
  877.  * Reset the object for reuse.
  878.  */
  879. RequestBackoff.prototype.reset = function() {
  880.   this.numErrors_ = 0;
  881.   this.errorTimeout_ = 0;
  882.   this.nextRequestTime_ = 0;
  883. }
  884.  
  885. /**
  886.  * Check to see if we can make a request.
  887.  */
  888. RequestBackoff.prototype.canMakeRequest = function() {
  889.   var now = Date.now();
  890.   if (now < this.nextRequestTime_) {
  891.     return false;
  892.   }
  893.  
  894.   return (this.requestTimes_.length < this.MAX_REQUESTS_ ||
  895.           (now - this.requestTimes_[0]) > this.REQUEST_PERIOD_);
  896. }
  897.  
  898. RequestBackoff.prototype.noteRequest = function() {
  899.   var now = Date.now();
  900.   this.requestTimes_.push(now);
  901.  
  902.   // We only care about keeping track of MAX_REQUESTS
  903.   if (this.requestTimes_.length > this.MAX_REQUESTS_)
  904.     this.requestTimes_.shift();
  905. }
  906.  
  907. RequestBackoff.prototype.nextRequestDelay = function() {
  908.   return Math.max(0, this.nextRequestTime_ - Date.now());
  909. }
  910.  
  911. /**
  912.  * Notify this object of the last server response.  If it's an error,
  913.  */
  914. RequestBackoff.prototype.noteServerResponse = function(status) {
  915.   if (this.isErrorStatus(status)) {
  916.     this.numErrors_++;
  917.  
  918.     if (this.numErrors_ < this.MAX_ERRORS_)
  919.       this.errorTimeout_ = this.RETRY_INCREMENT_;
  920.     else if (this.numErrors_ == this.MAX_ERRORS_)
  921.       this.errorTimeout_ = this.TIMEOUT_INCREMENT_;
  922.     else
  923.       this.errorTimeout_ *= 2;
  924.  
  925.     this.errorTimeout_ = Math.min(this.errorTimeout_, this.MAX_TIMEOUT_);
  926.     this.nextRequestTime_ = Date.now() + this.errorTimeout_;
  927.   } else {
  928.     // Reset error timeout, allow requests to go through.
  929.     this.reset();
  930.   }
  931. }
  932.  
  933. /**
  934.  * We consider 302, 303, 307, 4xx, and 5xx http responses to be errors.
  935.  * @param status Number http status
  936.  * @return Boolean true if we consider this http status an error
  937.  */
  938. RequestBackoff.prototype.isErrorStatus = function(status) {
  939.   return ((400 <= status && status <= 599) ||
  940.           HTTP_FOUND == status ||
  941.           HTTP_SEE_OTHER == status ||
  942.           HTTP_TEMPORARY_REDIRECT == status);
  943. }
  944.  
  945. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/url-crypto-key-manager.js"
  946.  
  947.  
  948. // This file implements the tricky business of managing the keys for our 
  949. // URL encryption. The protocol is:
  950. //
  951. // - Server generates secret key K_S
  952. // - Client starts up and requests a new key K_C from the server via HTTPS
  953. // - Server generates K_C and WrappedKey, which is K_C encrypted with K_S
  954. // - Server resonse with K_C and WrappedKey
  955. // - When client wants to encrypt a URL, it encrypts it with K_C and sends
  956. //   the encrypted URL along with WrappedKey
  957. // - Server decrypts WrappedKey with K_S to get K_C, and the URL with K_C
  958. //
  959. // This is, however, trickier than it sounds for two reasons. First,
  960. // we want to keep the number of HTTPS requests to an aboslute minimum
  961. // (like 1 or 2 per browser session). Second, the HTTPS request at
  962. // startup might fail, for example the user might be offline or a URL
  963. // fetch might need to be issued before the HTTPS request has
  964. // completed.
  965. //
  966. // We implement the following policy:
  967. // 
  968. // - Firefox will issue at most two HTTPS getkey requests per session
  969. // - Firefox will issue one HTTPS getkey request at startup if more than 24
  970. //   hours has passed since the last getkey request.
  971. // - Firefox will serialize to disk any key it gets
  972. // - Firefox will fall back on this serialized key until it has a
  973. //   fresh key
  974. // - The front-end can respond with a flag in a lookup request that tells
  975. //   the client to re-key. Firefox will issue a new HTTPS getkey request
  976. //   at this time if it has only issued one before
  977.  
  978. // We store the user key in this file.  The key can be used to verify signed
  979. // server updates.
  980. const kKeyFilename = "urlclassifierkey3.txt";
  981.  
  982. /**
  983.  * A key manager for UrlCrypto. There should be exactly one of these
  984.  * per appplication, and all UrlCrypto's should share it. This is
  985.  * currently implemented by having the manager attach itself to the
  986.  * UrlCrypto's prototype at startup. We could've opted for a global
  987.  * instead, but I like this better, even though it is spooky action
  988.  * at a distance.
  989.  * XXX: Should be an XPCOM service
  990.  *
  991.  * @param opt_keyFilename String containing the name of the 
  992.  *                        file we should serialize keys to/from. Used
  993.  *                        mostly for testing.
  994.  *
  995.  * @param opt_testing Boolean indicating whether we are testing. If we 
  996.  *                    are, then we skip trying to read the old key from
  997.  *                    file and automatically trying to rekey; presumably
  998.  *                    the tester will drive these manually.
  999.  *
  1000.  * @constructor
  1001.  */
  1002. function PROT_UrlCryptoKeyManager(opt_keyFilename, opt_testing) {
  1003.   this.debugZone = "urlcryptokeymanager";
  1004.   this.testing_ = !!opt_testing;
  1005.   this.clientKey_ = null;          // Base64-encoded, as fetched from server
  1006.   this.clientKeyArray_ = null;     // Base64-decoded into an array of numbers
  1007.   this.wrappedKey_ = null;         // Opaque websafe base64-encoded server key
  1008.   this.rekeyTries_ = 0;
  1009.   this.updating_ = false;
  1010.  
  1011.   // Don't do anything until keyUrl_ is set.
  1012.   this.keyUrl_ = null;
  1013.  
  1014.   this.keyFilename_ = opt_keyFilename ? 
  1015.                       opt_keyFilename : kKeyFilename;
  1016.  
  1017.   this.onNewKey_ = null;
  1018.  
  1019.   // Convenience properties
  1020.   this.MAX_REKEY_TRIES = PROT_UrlCryptoKeyManager.MAX_REKEY_TRIES;
  1021.   this.CLIENT_KEY_NAME = PROT_UrlCryptoKeyManager.CLIENT_KEY_NAME;
  1022.   this.WRAPPED_KEY_NAME = PROT_UrlCryptoKeyManager.WRAPPED_KEY_NAME;
  1023.  
  1024.   if (!this.testing_) {
  1025.     this.maybeLoadOldKey();
  1026.   }
  1027. }
  1028.  
  1029. // Do ***** NOT ***** set this higher; HTTPS is expensive
  1030. PROT_UrlCryptoKeyManager.MAX_REKEY_TRIES = 2;
  1031.  
  1032. // Base pref for keeping track of when we updated our key.
  1033. // We store the time as seconds since the epoch.
  1034. PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF = "urlclassifier.keyupdatetime.";
  1035.  
  1036. // Once every 30 days (interval in seconds)
  1037. PROT_UrlCryptoKeyManager.KEY_MIN_UPDATE_TIME = 30 * 24 * 60 * 60;
  1038.  
  1039. // These are the names the server will respond with in protocol4 format
  1040. PROT_UrlCryptoKeyManager.CLIENT_KEY_NAME = "clientkey";
  1041. PROT_UrlCryptoKeyManager.WRAPPED_KEY_NAME = "wrappedkey";
  1042.  
  1043. /**
  1044.  * Called to get ClientKey
  1045.  * @returns urlsafe-base64-encoded client key or null if we haven't gotten one.
  1046.  */
  1047. PROT_UrlCryptoKeyManager.prototype.getClientKey = function() {
  1048.   return this.clientKey_;
  1049. }
  1050.  
  1051. /**
  1052.  * Called by a UrlCrypto to get the current K_C
  1053.  *
  1054.  * @returns Array of numbers making up the client key or null if we 
  1055.  *          have no key
  1056.  */
  1057. PROT_UrlCryptoKeyManager.prototype.getClientKeyArray = function() {
  1058.   return this.clientKeyArray_;
  1059. }
  1060.  
  1061. /**
  1062.  * Called by a UrlCrypto to get WrappedKey
  1063.  *
  1064.  * @returns Opaque base64-encoded WrappedKey or null if we haven't
  1065.  *          gotten one
  1066.  */
  1067. PROT_UrlCryptoKeyManager.prototype.getWrappedKey = function() {
  1068.   return this.wrappedKey_;
  1069. }
  1070.  
  1071. /**
  1072.  * Change the key url.  When we do this, we go ahead and rekey.
  1073.  * @param keyUrl String
  1074.  */
  1075. PROT_UrlCryptoKeyManager.prototype.setKeyUrl = function(keyUrl) {
  1076.   // If it's the same key url, do nothing.
  1077.   if (keyUrl == this.keyUrl_)
  1078.     return;
  1079.  
  1080.   this.keyUrl_ = keyUrl;
  1081.   this.rekeyTries_ = 0;
  1082.  
  1083.   // Check to see if we should make a new getkey request.
  1084.   var prefs = new G_Preferences(PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF);
  1085.   var nextRekey = prefs.getPref(this.getPrefName_(this.keyUrl_), 0);
  1086.   if (nextRekey < parseInt(Date.now() / 1000, 10)) {
  1087.     this.reKey();
  1088.   }
  1089. }
  1090.  
  1091. /**
  1092.  * Given a url, return the pref value to use (pref contains last update time).
  1093.  * We basically use the url up until query parameters.  This avoids duplicate
  1094.  * pref entries as version number changes over time.
  1095.  * @param url String getkey URL
  1096.  */
  1097. PROT_UrlCryptoKeyManager.prototype.getPrefName_ = function(url) {
  1098.   var queryParam = url.indexOf("?");
  1099.   if (queryParam != -1) {
  1100.     return url.substring(0, queryParam);
  1101.   }
  1102.   return url;
  1103. }
  1104.  
  1105. /**
  1106.  * Tell the manager to re-key. For safety, this method still obeys the
  1107.  * max-tries limit. Clients should generally use maybeReKey() if they
  1108.  * want to try a re-keying: it's an error to call reKey() after we've
  1109.  * hit max-tries, but not an error to call maybeReKey().
  1110.  */
  1111. PROT_UrlCryptoKeyManager.prototype.reKey = function() {
  1112.   if (this.updating_) {
  1113.     G_Debug(this, "Already re-keying, ignoring this request");
  1114.     return true;
  1115.   }
  1116.  
  1117.   if (this.rekeyTries_ > this.MAX_REKEY_TRIES)
  1118.     throw new Error("Have already rekeyed " + this.rekeyTries_ + " times");
  1119.  
  1120.   this.rekeyTries_++;
  1121.  
  1122.   G_Debug(this, "Attempting to re-key");
  1123.   // If the keyUrl isn't set, we don't do anything.
  1124.   if (!this.testing_ && this.keyUrl_) {
  1125.     this.fetcher_ = new PROT_XMLFetcher();
  1126.     this.fetcher_.get(this.keyUrl_, BindToObject(this.onGetKeyResponse, this));
  1127.     this.updating_ = true;
  1128.  
  1129.     // Calculate the next time we're allowed to re-key.
  1130.     var prefs = new G_Preferences(PROT_UrlCryptoKeyManager.NEXT_REKEY_PREF);
  1131.     var nextRekey = parseInt(Date.now() / 1000, 10)
  1132.                   + PROT_UrlCryptoKeyManager.KEY_MIN_UPDATE_TIME;
  1133.     prefs.setPref(this.getPrefName_(this.keyUrl_), nextRekey);
  1134.   }
  1135. }
  1136.  
  1137. /**
  1138.  * Try to re-key if we haven't already hit our limit. It's OK to call
  1139.  * this method multiple times, even if we've already tried to rekey
  1140.  * more than the max. It will simply refuse to do so.
  1141.  *
  1142.  * @returns Boolean indicating if it actually issued a rekey request (that
  1143.  *          is, if we haven' already hit the max)
  1144.  */
  1145. PROT_UrlCryptoKeyManager.prototype.maybeReKey = function() {
  1146.   if (this.rekeyTries_ > this.MAX_REKEY_TRIES) {
  1147.     G_Debug(this, "Not re-keying; already at max");
  1148.     return false;
  1149.   }
  1150.  
  1151.   this.reKey();
  1152.   return true;
  1153. }
  1154.  
  1155. /**
  1156.  * Drop the existing set of keys.  Resets the rekeyTries variable to
  1157.  * allow a rekey to succeed.
  1158.  */
  1159. PROT_UrlCryptoKeyManager.prototype.dropKey = function() {
  1160.   this.rekeyTries_ = 0;
  1161.   this.replaceKey_(null, null);
  1162. }
  1163.  
  1164. /**
  1165.  * @returns Boolean indicating if we have a key we can use 
  1166.  */
  1167. PROT_UrlCryptoKeyManager.prototype.hasKey = function() {
  1168.   return this.clientKey_ != null && this.wrappedKey_ != null;
  1169. }
  1170.  
  1171. PROT_UrlCryptoKeyManager.prototype.unUrlSafe = function(key)
  1172. {
  1173.     return key ? key.replace("-", "+").replace("_", "/") : "";
  1174. }
  1175.  
  1176. /**
  1177.  * Set a new key and serialize it to disk.
  1178.  *
  1179.  * @param clientKey String containing the base64-encoded client key 
  1180.  *                  we wish to use
  1181.  *
  1182.  * @param wrappedKey String containing the opaque base64-encoded WrappedKey
  1183.  *                   the server gave us (i.e., K_C encrypted with K_S)
  1184.  */
  1185. PROT_UrlCryptoKeyManager.prototype.replaceKey_ = function(clientKey, 
  1186.                                                           wrappedKey) {
  1187.   if (this.clientKey_)
  1188.     G_Debug(this, "Replacing " + this.clientKey_ + " with " + clientKey);
  1189.  
  1190.   this.clientKey_ = clientKey;
  1191.   this.clientKeyArray_ = Array.map(atob(this.unUrlSafe(clientKey)),
  1192.                                    function(c) { return c.charCodeAt(0); });
  1193.   this.wrappedKey_ = wrappedKey;
  1194.  
  1195.   this.serializeKey_(this.clientKey_, this.wrappedKey_);
  1196.  
  1197.   if (this.onNewKey_) {
  1198.     this.onNewKey_();
  1199.   }
  1200. }
  1201.  
  1202. /**
  1203.  * Try to write the key to disk so we can fall back on it. Fail
  1204.  * silently if we cannot. The keys are serialized in protocol4 format.
  1205.  *
  1206.  * @returns Boolean indicating whether we succeeded in serializing
  1207.  */
  1208. PROT_UrlCryptoKeyManager.prototype.serializeKey_ = function() {
  1209.  
  1210.   var map = {};
  1211.   map[this.CLIENT_KEY_NAME] = this.clientKey_;
  1212.   map[this.WRAPPED_KEY_NAME] = this.wrappedKey_;
  1213.   
  1214.   try {  
  1215.  
  1216.     var keyfile = Cc["@mozilla.org/file/directory_service;1"]
  1217.                  .getService(Ci.nsIProperties)
  1218.                  .get("ProfD", Ci.nsILocalFile); /* profile directory */
  1219.     keyfile.append(this.keyFilename_);
  1220.  
  1221.     if (!this.clientKey_ || !this.wrappedKey_) {
  1222.       keyfile.remove(true);
  1223.       return;
  1224.     }
  1225.  
  1226.     var data = (new G_Protocol4Parser()).serialize(map);
  1227.  
  1228.     try {
  1229.       var stream = Cc["@mozilla.org/network/file-output-stream;1"]
  1230.                    .createInstance(Ci.nsIFileOutputStream);
  1231.       stream.init(keyfile,
  1232.                   0x02 | 0x08 | 0x20 /* PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE */,
  1233.                   -1 /* default perms */, 0 /* no special behavior */);
  1234.       stream.write(data, data.length);
  1235.     } finally {
  1236.       stream.close();
  1237.     }
  1238.     return true;
  1239.  
  1240.   } catch(e) {
  1241.  
  1242.     G_Error(this, "Failed to serialize new key: " + e);
  1243.     return false;
  1244.  
  1245.   }
  1246. }
  1247.  
  1248. /**
  1249.  * Invoked when we've received a protocol4 response to our getkey
  1250.  * request. Try to parse it and set this key as the new one if we can.
  1251.  *
  1252.  *  @param responseText String containing the protocol4 getkey response
  1253.  */ 
  1254. PROT_UrlCryptoKeyManager.prototype.onGetKeyResponse = function(responseText) {
  1255.  
  1256.   var response = (new G_Protocol4Parser).parse(responseText);
  1257.   var clientKey = response[this.CLIENT_KEY_NAME];
  1258.   var wrappedKey = response[this.WRAPPED_KEY_NAME];
  1259.  
  1260.   this.updating_ = false;
  1261.   this.fetcher_ = null;
  1262.  
  1263.   if (response && clientKey && wrappedKey) {
  1264.     G_Debug(this, "Got new key from: " + responseText);
  1265.     this.replaceKey_(clientKey, wrappedKey);
  1266.   } else {
  1267.     G_Debug(this, "Not a valid response for /newkey");
  1268.   }
  1269. }
  1270.  
  1271. /**
  1272.  * Set the callback to be called whenever we get a new key.
  1273.  *
  1274.  * @param callback The callback.
  1275.  */
  1276. PROT_UrlCryptoKeyManager.prototype.onNewKey = function(callback) 
  1277. {
  1278.   this.onNewKey_ = callback;
  1279. }
  1280.  
  1281. /**
  1282.  * Attempt to read a key we've previously serialized from disk, so
  1283.  * that we can fall back on it in case we can't get one from the
  1284.  * server. If we get a key, only use it if we don't already have one
  1285.  * (i.e., if our startup HTTPS request died or hasn't yet completed).
  1286.  *
  1287.  * This method should be invoked early, like when the user's profile
  1288.  * becomes available.
  1289.  */ 
  1290. PROT_UrlCryptoKeyManager.prototype.maybeLoadOldKey = function() {
  1291.   
  1292.   var oldKey = null;
  1293.   try {  
  1294.     var keyfile = Cc["@mozilla.org/file/directory_service;1"]
  1295.                  .getService(Ci.nsIProperties)
  1296.                  .get("ProfD", Ci.nsILocalFile); /* profile directory */
  1297.     keyfile.append(this.keyFilename_);
  1298.     if (keyfile.exists()) {
  1299.       try {
  1300.         var fis = Cc["@mozilla.org/network/file-input-stream;1"]
  1301.                   .createInstance(Ci.nsIFileInputStream);
  1302.         fis.init(keyfile, 0x01 /* PR_RDONLY */, 0444, 0);
  1303.         var stream = Cc["@mozilla.org/scriptableinputstream;1"]
  1304.                      .createInstance(Ci.nsIScriptableInputStream);
  1305.         stream.init(fis);
  1306.         oldKey = stream.read(stream.available());
  1307.       } finally {
  1308.         if (stream)
  1309.           stream.close();
  1310.       }
  1311.     }
  1312.   } catch(e) {
  1313.     G_Debug(this, "Caught " + e + " trying to read keyfile");
  1314.     return;
  1315.   }
  1316.    
  1317.   if (!oldKey) {
  1318.     G_Debug(this, "Couldn't find old key.");
  1319.     return;
  1320.   }
  1321.  
  1322.   oldKey = (new G_Protocol4Parser).parse(oldKey);
  1323.   var clientKey = oldKey[this.CLIENT_KEY_NAME];
  1324.   var wrappedKey = oldKey[this.WRAPPED_KEY_NAME];
  1325.  
  1326.   if (oldKey && clientKey && wrappedKey && !this.hasKey()) {
  1327.     G_Debug(this, "Read old key from disk.");
  1328.     this.replaceKey_(clientKey, wrappedKey);
  1329.   }
  1330. }
  1331.  
  1332. PROT_UrlCryptoKeyManager.prototype.shutdown = function() {
  1333.   if (this.fetcher_) {
  1334.     this.fetcher_.cancel();
  1335.     this.fetcher_ = null;
  1336.   }
  1337. }
  1338.  
  1339.  
  1340. //@line 36 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/content/xml-fetcher.js"
  1341.  
  1342. // A simple class that encapsulates a request. You'll notice the
  1343. // style here is different from the rest of the extension; that's
  1344. // because this was re-used from really old code we had. At some
  1345. // point it might be nice to replace this with something better
  1346. // (e.g., something that has explicit onerror handler, ability
  1347. // to set headers, and so on).
  1348. //
  1349. // The only interesting thing here is its ability to strip cookies
  1350. // from the request.
  1351.  
  1352. /**
  1353.  * Because we might be in a component, we can't just assume that
  1354.  * XMLHttpRequest exists. So we use this tiny factory function to wrap the
  1355.  * XPCOM version.
  1356.  *
  1357.  * @return XMLHttpRequest object
  1358.  */
  1359. function PROT_NewXMLHttpRequest() {
  1360.   var Cc = Components.classes;
  1361.   var Ci = Components.interfaces;
  1362.   var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
  1363.                 .createInstance(Ci.nsIXMLHttpRequest);
  1364.   // Need the following so we get onerror/load/progresschange
  1365.   request.QueryInterface(Ci.nsIJSXMLHttpRequest);
  1366.   return request;
  1367. }
  1368.  
  1369. /**
  1370.  * A helper class that does HTTP GETs and calls back a function with
  1371.  * the content it receives. Asynchronous, so uses a closure for the
  1372.  * callback.
  1373.  *
  1374.  * @param opt_stripCookies Boolean indicating whether we should strip
  1375.  *                         cookies from this request
  1376.  * 
  1377.  * @constructor
  1378.  */
  1379. function PROT_XMLFetcher(opt_stripCookies) {
  1380.   this.debugZone = "xmlfetcher";
  1381.   this._request = PROT_NewXMLHttpRequest();
  1382.   this._stripCookies = !!opt_stripCookies;
  1383. }
  1384.  
  1385. PROT_XMLFetcher.prototype = {
  1386.   /**
  1387.    * Function that will be called back upon fetch completion.
  1388.    */
  1389.   _callback: null,
  1390.   
  1391.  
  1392.   /**
  1393.    * Fetches some content.
  1394.    * 
  1395.    * @param page URL to fetch
  1396.    * @param callback Function to call back when complete.
  1397.    */
  1398.   get: function(page, callback) {
  1399.     this._request.abort();                // abort() is asynchronous, so
  1400.     this._request = PROT_NewXMLHttpRequest();
  1401.     this._callback = callback;
  1402.     var asynchronous = true;
  1403.     this._request.open("GET", page, asynchronous);
  1404.     this._request.channel.notificationCallbacks = this;
  1405.  
  1406.     if (this._stripCookies)
  1407.       new PROT_CookieStripper(this._request.channel);
  1408.  
  1409.     // Create a closure
  1410.     var self = this;
  1411.     this._request.onreadystatechange = function() {
  1412.       self.readyStateChange(self);
  1413.     }
  1414.  
  1415.     this._request.send(null);
  1416.   },
  1417.  
  1418.   cancel: function() {
  1419.     this._request.onreadystatechange = null;
  1420.     this._request.abort();
  1421.     this._request = null;
  1422.   },
  1423.  
  1424.   /**
  1425.    * Called periodically by the request to indicate some state change. 4
  1426.    * means content has been received.
  1427.    */
  1428.   readyStateChange: function(fetcher) {
  1429.     if (fetcher._request.readyState != 4)
  1430.       return;
  1431.  
  1432.     // If the request fails, on trunk we get status set to
  1433.     // NS_ERROR_NOT_AVAILABLE.  On 1.8.1 branch we get an exception
  1434.     // forwarded from nsIHttpChannel::GetResponseStatus.  To be consistent
  1435.     // between branch and trunk, we send back NS_ERROR_NOT_AVAILABLE for
  1436.     // http failures.
  1437.     var responseText = null;
  1438.     var status = Components.results.NS_ERROR_NOT_AVAILABLE;
  1439.     try {
  1440.       G_Debug(this, "xml fetch status code: \"" + 
  1441.               fetcher._request.status + "\"");
  1442.       status = fetcher._request.status;
  1443.       responseText = fetcher._request.responseText;
  1444.     } catch(e) {
  1445.       G_Debug(this, "Caught exception trying to read xmlhttprequest " +
  1446.               "status/response.");
  1447.       G_Debug(this, e);
  1448.     }
  1449.     if (fetcher._callback)
  1450.       fetcher._callback(responseText, status);
  1451.   },
  1452.  
  1453.   // Suppress any certificate errors
  1454.   notifyCertProblem: function(socketInfo, status, targetSite) {
  1455.     return true;
  1456.   },
  1457.  
  1458.   // Suppress any ssl errors
  1459.   notifySSLError: function(socketInfo, error, targetSite) {
  1460.     return true;
  1461.   },
  1462.  
  1463.   // nsIInterfaceRequestor
  1464.   getInterface: function(iid) {
  1465.     return this.QueryInterface(iid);
  1466.   },
  1467.  
  1468.   QueryInterface: function(iid) {
  1469.     if (!iid.equals(Components.interfaces.nsIBadCertListener2) &&
  1470.         !iid.equals(Components.interfaces.nsISSLErrorListener) &&
  1471.         !iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
  1472.         !iid.equals(Components.interfaces.nsISupports))
  1473.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1474.     return this;
  1475.   }
  1476. };
  1477.  
  1478.  
  1479. /**
  1480.  * This class knows how to strip cookies from an HTTP request. It
  1481.  * listens for http-on-modify-request, and modifies the request
  1482.  * accordingly. We can't do this using xmlhttprequest.setHeader() or
  1483.  * nsIChannel.setRequestHeader() before send()ing because the cookie
  1484.  * service is called after send().
  1485.  * 
  1486.  * @param channel nsIChannel in which the request is happening
  1487.  * @constructor
  1488.  */
  1489. function PROT_CookieStripper(channel) {
  1490.   this.debugZone = "cookiestripper";
  1491.   this.topic_ = "http-on-modify-request";
  1492.   this.channel_ = channel;
  1493.  
  1494.   var Cc = Components.classes;
  1495.   var Ci = Components.interfaces;
  1496.   this.observerService_ = Cc["@mozilla.org/observer-service;1"]
  1497.                           .getService(Ci.nsIObserverService);
  1498.   this.observerService_.addObserver(this, this.topic_, false);
  1499.  
  1500.   // If the request doesn't issue, don't hang around forever
  1501.   var twentySeconds = 20 * 1000;
  1502.   this.alarm_ = new G_Alarm(BindToObject(this.stopObserving, this), 
  1503.                             twentySeconds);
  1504. }
  1505.  
  1506. /**
  1507.  * Invoked by the observerservice. See nsIObserve.
  1508.  */
  1509. PROT_CookieStripper.prototype.observe = function(subject, topic, data) {
  1510.   if (topic != this.topic_ || subject != this.channel_)
  1511.     return;
  1512.  
  1513.   G_Debug(this, "Stripping cookies for channel.");
  1514.  
  1515.   this.channel_.QueryInterface(Components.interfaces.nsIHttpChannel);
  1516.   this.channel_.setRequestHeader("Cookie", "", false /* replace, not add */);
  1517.   this.alarm_.cancel();
  1518.   this.stopObserving();
  1519. }
  1520.  
  1521. /**
  1522.  * Remove us from the observerservice
  1523.  */
  1524. PROT_CookieStripper.prototype.stopObserving = function() {
  1525.   G_Debug(this, "Removing observer");
  1526.   this.observerService_.removeObserver(this, this.topic_);
  1527.   this.channel_ = this.alarm_ = this.observerService_ = null;
  1528. }
  1529.  
  1530. /**
  1531.  * XPCOM cruft
  1532.  */
  1533. PROT_CookieStripper.prototype.QueryInterface = function(iid) {
  1534.   var Ci = Components.interfaces;
  1535.   if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIObserve))
  1536.     return this;
  1537.   throw Components.results.NS_ERROR_NO_INTERFACE;
  1538. }
  1539.  
  1540. //@line 57 "/build/buildd/xulrunner-1.9.1-1.9.1.5+nobinonly/build-tree/mozilla/toolkit/components/url-classifier/src/nsUrlClassifierLib.js"
  1541.  
  1542. // Expose this whole component.
  1543. var lib = this;
  1544.  
  1545. function UrlClassifierLib() {
  1546.   this.wrappedJSObject = lib;
  1547. }
  1548.  
  1549. // Module object
  1550. function UrlClassifierLibMod() {
  1551.   this.firstTime = true;
  1552.   this.cid = Components.ID("{26a4a019-2827-4a89-a85c-5931a678823a}");
  1553.   this.progid = "@mozilla.org/url-classifier/jslib;1";
  1554. }
  1555.  
  1556. UrlClassifierLibMod.prototype.registerSelf = function(compMgr, fileSpec, loc, type) {
  1557.   if (this.firstTime) {
  1558.     this.firstTime = false;
  1559.     throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  1560.   }
  1561.   compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1562.   compMgr.registerFactoryLocation(this.cid,
  1563.                                   "UrlClassifier JS Lib",
  1564.                                   this.progid,
  1565.                                   fileSpec,
  1566.                                   loc,
  1567.                                   type);
  1568. };
  1569.  
  1570. UrlClassifierLibMod.prototype.getClassObject = function(compMgr, cid, iid) {  
  1571.   if (!cid.equals(this.cid))
  1572.     throw Components.results.NS_ERROR_NO_INTERFACE;
  1573.   if (!iid.equals(Ci.nsIFactory))
  1574.     throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  1575.  
  1576.   return this.factory;
  1577. }
  1578.  
  1579. UrlClassifierLibMod.prototype.canUnload = function(compMgr) {
  1580.   return true;
  1581. }
  1582.  
  1583. UrlClassifierLibMod.prototype.factory = {
  1584.   createInstance: function(outer, iid) {
  1585.     if (outer != null)
  1586.       throw Components.results.NS_ERROR_NO_AGGREGATION;
  1587.     return new UrlClassifierLib();
  1588.   }
  1589. };
  1590.  
  1591. var LibModInst = new UrlClassifierLibMod();
  1592.  
  1593. function NSGetModule(compMgr, fileSpec) {
  1594.   return LibModInst;
  1595. }
  1596.